package src.E_Thread;

// 死锁：多个线程互相抱着对方需要的资源，然后形成僵持

/*
    好比是甲同学和乙同学在打扫卫生，甲同学拿着扫帚等乙同学的簸箕，而乙同学拿着簸箕在等甲同学的扫帚
    死锁产生的条件：
        1、互斥条件：同一时刻一线程只能占用一个资源。
            同一时刻，甲拿着扫帚，乙拿着簸箕。
        2、请求与保持：一个线程因请求资源而阻塞时，对已获得的资源保持不放。
            甲在等乙的簸箕，但甲不会让出自己的扫帚
        3、不可剥夺：已获得的资源在为使用完时，其他线程不能强行剥夺。
            甲拿着扫帚，但是甲不能去强抢乙拿的簸箕
        4、循环等待
            甲拿着扫帚在等乙的簸箕，而乙拿着簸箕等甲的扫帚，形成闭环
    避免死锁的方法：
        破坏互斥条件：无法被破坏，因为锁就是通过互斥来解决线程安全问题
        破坏请求与保持条件：一次申请所有需要的资源
        破坏不可剥夺条件：如果线程已占用部分资源，且他还要申请其他资源，如果申请不到，就主动释放它自己占有的资源
        破坏循环等待条件：按照顺序申请资源，释放资源则逆序
*/
public class E16_DeadLock {
    public static void main(String[] args) {
        ExamplesDeadLock jia = new ExamplesDeadLock(false,"甲");
        ExamplesDeadLock yi = new ExamplesDeadLock(true,"乙");
        jia.start();
        yi.start();
    }
}

// 扫帚
class Broom{}
// 簸箕
class Dustpan{}

// 死锁示例
class ExamplesDeadLock extends Thread{
    static Broom broom = new Broom();
    static Dustpan dustpan = new Dustpan();
    private boolean flag;
    private String name;
    public ExamplesDeadLock(boolean flag, String name){
        this.flag = flag;
        this.name = name;
    }
    @Override
    public void run() {
        if (flag){
            // 甲手里是扫帚
            synchronized (broom){
                System.out.println(this.name+" 拿到了扫帚");
                // 模拟延迟
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                // 甲再去拿簸箕 （ps：解决方案一把这个锁放现在这个锁的外面）
                synchronized (dustpan){
                    System.out.println(this.name+" 拿到了簸箕");
                }
            }
        } else {
            // 乙手里是簸箕
            synchronized (dustpan){
                System.out.println(this.name+" 拿到了簸箕");
                // 模拟延迟
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                // 乙再去拿扫帚 （ps：解决方案二把这个锁放现在这个锁的外面）
                synchronized (broom){
                    System.out.println(this.name+" 拿到了扫帚");
                }
            }
        }
    }
}